package any.functor.impl.pred;

import java.util.Map.Entry;

import any.ImmutableAny;
import any.functor.interfaces.InclusiveExclusivePredicate;
import any.functor.interfaces.Predicate;
import any.functor.interfaces.PredicateAndBuilder;
import any.functor.interfaces.PredicateAndInclusiveExclusiveBuilder;

class PredicateAndInclusiveExclusiveBuilderImplementation 
	implements PredicateAndInclusiveExclusiveBuilder<Entry<String, ? extends ImmutableAny>, Number> {

    final Number value1;
    Type fromType = Type.INCLUSIVE;
    Type toType = Type.INCLUSIVE;

    PredicateAndInclusiveExclusiveBuilderImplementation(Number value1) {
	    this.value1 = value1;
    }

    public InclusiveExclusivePredicate<Entry<String, ? extends ImmutableAny>> and(final Number value2) {
    	return new PredicateImpl(value1, value2);
    }

    public PredicateAndBuilder<Entry<String, ? extends ImmutableAny>, Number> exclusive() {
    	fromType = Type.EXCLUSIVE;
        return this;
    }

    public PredicateAndBuilder<Entry<String, ? extends ImmutableAny>, Number> inclusive() {
    	fromType = Type.INCLUSIVE;
        return this;
    }

    class PredicateImpl extends BasePredicate<Entry<String, ? extends ImmutableAny>> implements InclusiveExclusivePredicate<Entry<String, ? extends ImmutableAny>> {
    	private final Number value1;
        private final Number value2;
    	public PredicateImpl(Number value1, Number value2) {
    		this.value1 = value1;
			this.value2 = value2;
        }
    	public InclusiveExclusivePredicate<Entry<String, ? extends ImmutableAny>> exclusive() {
    		toType = Type.EXCLUSIVE;
            return this;
        }
    	public InclusiveExclusivePredicate<Entry<String, ? extends ImmutableAny>> inclusive() {
    		toType = Type.INCLUSIVE;
            return this;
        }
    	public boolean apply(Entry<String, ? extends ImmutableAny> a) {
    		return buildPredicate().apply(a);
        }
    	@Override
    	public String toString() {
    		return buildPredicate().toString();
    	}
		private Predicate<Entry<String, ? extends ImmutableAny>> buildPredicate() {
	        return fromType.from(value1).and(toType.to(value2));
        }
    }
    
    enum Type { 
    	INCLUSIVE {
    		@Override public Predicate<Entry<String, ? extends ImmutableAny>> from(Number value) {
    			return NumberAnyPredicates.greaterOrEqualThan(value);
    		}
    		@Override public Predicate<Entry<String, ? extends ImmutableAny>> to(Number value) {
    			return NumberAnyPredicates.smallerOrEqualThan(value);
    		}
    	}
    	, 
    	EXCLUSIVE{
    		@Override public Predicate<Entry<String, ? extends ImmutableAny>> from(Number value) {
    			return NumberAnyPredicates.greaterThan(value);
    		}
    		@Override public Predicate<Entry<String, ? extends ImmutableAny>> to(Number value) {
    			return NumberAnyPredicates.greaterOrEqualThan(value);
    		}
    	}
    	;
    	
    	abstract Predicate<Entry<String, ? extends ImmutableAny>> from(Number value);
    	abstract Predicate<Entry<String, ? extends ImmutableAny>> to(Number value);
    }
}

